<?php

declare(strict_types=1);

/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Server\ServerFactory;
use Hyperf\Utils\ApplicationContext;
use Psr\Http\Message\ServerRequestInterface;
use Swoole\Websocket\Frame;
use Swoole\WebSocket\Server as WebSocketServer;

/**
 * 容器实例.
 */
if (!function_exists('container')) {
    function container()
    {
        return ApplicationContext::getContainer();
    }
}

/**
 * redis 客户端实例.
 */
if (!function_exists('redis')) {
    function redis()
    {
        return container()->get(Redis::class);
    }
}

/**
 * server 实例 基于 swoole server.
 */
if (!function_exists('server')) {
    function server()
    {
        return container()->get(ServerFactory::class)->getServer()->getServer();
    }
}

/**
 * websocket frame 实例.
 */
if (!function_exists('frame')) {
    function frame()
    {
        return container()->get(Frame::class);
    }
}

/**
 * websocket 实例.
 */
if (!function_exists('websocket')) {
    function websocket()
    {
        return container()->get(WebSocketServer::class);
    }
}

/**
 * 缓存实例 简单的缓存.
 */
if (!function_exists('cache')) {
    function cache()
    {
        return container()->get(Psr\SimpleCache\CacheInterface::class);
    }
}

/**
 * 控制台日志.
 */
if (!function_exists('stdLog')) {
    function stdLog()
    {
        return container()->get(StdoutLoggerInterface::class);
    }
}

/**
 * 文件日志.
 */
if (!function_exists('logger')) {
    function logger()
    {
        return container()->get(LoggerFactory::class)->make();
    }
}

if (!function_exists('request')) {
    function request()
    {
        return container()->get(ServerRequestInterface::class);
    }
}

if (!function_exists('response')) {
    function response()
    {
        return container()->get(ResponseInterface::class);
    }
}

if (!function_exists('getUUID')) {
    function getUUID($prefix = '')
    {
        return $prefix . '_' . uniqid(date('YmdHis'));
    }
}

if (!function_exists('authUser')) {
    /**
     * @return HyUser
     */
    function authUser()
    {
        $request = container()->get(\Hyperf\HttpServer\Contract\RequestInterface::class);
        $token = $request->getHeader('Authorization')[0] ?? '';
        if (!$token) {
            throw new TokenValidException('JWT验证失败', ResponseCode::UNAUTHORIZED);
        }
        $jwt = container()->get(Jwt::class);
        $token = $jwt->getTokenObj();
        return HyUser::getFirstById($token->getClaim('id'));
    }
}

if (!function_exists('big_number')) {
    // 默认的精度为小数点后两位
    function big_number($number, $scale = 2)
    {
        return new \Moontoast\Math\BigNumber($number, $scale);
    }
}

if (!function_exists('array_only')) {
    function array_only(array $arr, array $keys)
    {
        $new_arr = [];
        foreach ($arr as $k => $v) {
            if (in_array($k, $keys)) {
                $new_arr[$k] = $v;
            }
        }
        return $new_arr;
    }
}

if (!function_exists('success')) {
    /**
     * 成功通用格式.
     * @param string $msg
     * @param null $data
     * @param array $exts
     * @return array
     */
    function success(string $message = 'OK', $data = null, array $exts = []): array
    {
        $res = [
            'code' => 0,
            'message' => $message,
            'data' => $data,
        ];
        foreach ($exts as $k => $ext) {
            $res[$k] = $ext;
        }
        return $res;
    }
}
if (!function_exists('error')) {
    /**
     * 失败通用格式.
     * @param string $message
     * @param null $data
     * @param array $exts
     * @return array
     */
    function error(string $message = 'Err', $data = null, array $exts = []): array
    {
        $res = [
            'code' => 1,
            'message' => $message,
            'data' => $data,
        ];
        foreach ($exts as $k => $ext) {
            $res[$k] = $ext;
        }
        return $res;
    }
}

if (!function_exists('arrayMergeKeys')) {
    /**
     * 指定keys列表数组合并.
     * @param $array1
     * @param $array2
     * @param array $keys
     * @return array
     */
    function arrayMergeKeys($array1, $array2, array $keys): array
    {
        $tempArr = [];
        foreach ($keys as $key) {
            if (isset($array2[$key])) {
                $tempArr[$key] = $array2[$key];
            }
        }
        return array_merge($array1, $tempArr);
    }
}

if (!function_exists('convertToArray')) {
    /**
     * 不同类型变量转数组.
     * @param $data
     * @return array
     * @throws Exception
     */
    function convertToArray($data): array
    {
        switch (true) {
            case is_array($data):
                return $data;
            case $data instanceof stdClass:
                return (array)$data;
            case $data instanceof Collection:
                return $data->all();
            case $data instanceof Arrayable:
            case $data instanceof \Hyperf\Database\Model\Model:
                return $data->toArray();
            case $data instanceof \IteratorAggregate && $data->getIterator() instanceof \ArrayIterator:
                return $data->getIterator()->getArrayCopy();
            case $data instanceof \ArrayIterator:
                return $data->getArrayCopy();
            default:
                return [];
        }
    }
}

if (!function_exists('arrayFilter')) {
    /**
     * 数组空值过滤 可以.
     * @param array $array
     * @param array $exclude
     * @param array $filters
     * @return array
     */
    function arrayFilter(array $array, array $exclude = [], array $filters = [0, '', null]): array
    {
        foreach ($array as $key => $value) {
            if (!in_array($key, $exclude) && in_array($value, $filters, true)) {
                unset($array[$key]);
            }
        }
        return $array;
    }
}
if (!function_exists('birthday')) {
    function birthday($mydate)
    {
        $birth = $mydate;
        [$by, $bm, $bd] = explode('-', $birth);
        $cm = date('n');
        $cd = date('j');
        $age = date('Y') - $by - 1;
        if ($cm > $bm || $cm == $bm && $cd > $bd) {
            ++$age;
        }
        return $age;
    }
}
